package cn.com.sinux.spring.utils.fileconvert;

import cn.com.sinux.spring.utils.FileUtils;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.DispatchEvents;
import com.jacob.com.Variant;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

/**
 * Created by Administrator on 2014/7/10.
 */
public class PDFCreatorConvertEngine extends ConvertEngine {

    public static final Integer PDF_FORMAT = 0;
    public static final Integer PNG_FORMAT = 1;
    public static final Integer JPG_FORMAT = 2;
    public static final Integer BMP_FORMAT = 3;
    public static final Integer PCX_FORMAT = 4;
    public static final Integer TIF_FORMAT = 5;
    public static final Integer PS_FORMAT = 6;
    public static final Integer EPS_FORMAT = 7;
    public static final Integer TXT_FORMAT = 8;
    public static final Integer PSD_FORMAT = 9;
    public static final Integer PCL_FORMAT = 10;
    public static final Integer RAW_FORMAT = 11;
    public static final Integer SVG_FORMAT = 12;

    private static boolean addPathToLib = false;
    private static String optPath;
    public static final int STATUS_IN_PROGRESS = 2;
    public static final int STATUS_WITH_ERRORS = 1;
    public static final int STATUS_READY = 0;
    private ActiveXComponent pdfCreator;
    private DispatchEvents dispatcher;
    private volatile int status;
    private Variant defaultPrinter;

    private static final Logger logger = LoggerFactory.getLogger(PDFCreatorConvertEngine.class);

    public PDFCreatorConvertEngine(String optPath) {
        if (!addPathToLib) {
            try {
                Field field = ClassLoader.class.getDeclaredField("usr_paths");
                field.setAccessible(true);
                String[] paths = (String[]) field.get(null);
                for (String path : paths) {
                    if (optPath.equals(path)) {
                        addPathToLib = true;
                        return;
                    }
                }
                String[] tmp = new String[paths.length + 1];
                System.arraycopy(paths, 0, tmp, 0, paths.length);
                tmp[paths.length] = optPath;
                field.set(null, tmp);
                addPathToLib = true;
            } catch (IllegalAccessException e) {
                logger.error("指定路径缺少jacob.dll");
            } catch (NoSuchFieldException e) {
                logger.error("指定路径缺少jacob.dll");
            }
        }
    }

    private void init(Integer type) {
        pdfCreator = new ActiveXComponent("PDFCreator.clsPDFCreator");
        dispatcher = new DispatchEvents(pdfCreator, this);
        pdfCreator.setProperty("cVisible", new Variant(false));
        pdfCreator.invoke("cStart", new Variant[]{new Variant("/NoProcessingAtStartup"), new Variant(true)});
        setCOption("UseAutosave", 1);
        setCOption("UseAutosaveDirectory", 1);
        setCOption("AutosaveFormat", type);
        defaultPrinter = pdfCreator.getProperty("cDefaultPrinter");
        status = STATUS_IN_PROGRESS;
        pdfCreator.setProperty("cDefaultprinter", "PDFCreator");
        pdfCreator.invoke("cClearCache");
        pdfCreator.setProperty("cPrinterStop", false);
    }

    private void setCOption(String property, Object value) {
        Dispatch.invoke(pdfCreator, "cOption", Dispatch.Put, new Object[]{property, value}, new int[2]);
    }

    private void close() {
        if (pdfCreator != null) {
            pdfCreator.setProperty("cDefaultprinter", defaultPrinter);
            pdfCreator.invoke("cClearCache");
            pdfCreator.setProperty("cPrinterStop", true);
            pdfCreator.invoke("cClose");
            pdfCreator.safeRelease();
            pdfCreator = null;
        }
        if (dispatcher != null) {
            dispatcher.safeRelease();
            dispatcher = null;
        }
    }

    public void convert(ConvertType convertType, ConvertObject convertObject) throws Exception {
        String extName = FileUtils.getExtName(convertObject.getSource());
        if (StringUtils.isNotBlank(extName)) {
            logger.error("不能转换的类型");
            convertObject.failure("不能转换的类型");
            return;
        }
        if (ConvertType.toPdf.equals(convertType)) {
            if (ConvertResultType.PDF.name().equals(extName.toUpperCase().toUpperCase())) {
                File file = new File(convertObject.getSource());
                //如果存在，则直接拷贝一个资源过去
                String dsName = UUID.randomUUID().toString() + ".pdf";
                FileUtils.copy(file, new File(convertObject.getDesDir() + "/" + dsName), false);
                convertObject.success(Collections.singletonList(dsName));
                return;
            }
            convertObject.success(convertToPdf(convertObject));
        } else if (ConvertType.toImage.equals(convertType)) {
            convertObject.success(convertToImage(convertObject));
        } else if (ConvertType.toSwf.equals(convertType)) {
            convertObject.success(convertToSwf(convertObject));
        } else {
            convertObject.success(convertToHtml(convertObject));
        }
    }

    private String convertToPdf(ConvertObject convertObject) throws Exception {
        String fileuuid = UUID.randomUUID().toString() + ".pdf";
        _convert(PDF_FORMAT, convertObject.getSource(), convertObject.getDesDir() + "/" + fileuuid);
        return fileuuid;
    }

    private String convertToHtml(ConvertObject convertObject) throws Exception {
        return "";
    }

    private String convertToSwf(ConvertObject convertObject) throws Exception {
        return pdf2Swf(getPath(convertObject), convertObject.getDesDir(), false);
    }

    private File getPdfFiles(String destPath) {
        File file = new File(destPath);
        Collection<File> files = FileUtils.listFiles(file, new String[]{"pdf"}, false);
        return files.isEmpty() ? null : files.iterator().next();
    }


    private String getPath(ConvertObject convertObject) throws Exception {
        String extName = FileUtils.getExtName(convertObject.getSource());
        String _dest;
        if ("pdf".equals(extName.toLowerCase())) {
            _dest = convertObject.getSource();
        } else {
            File file = getPdfFiles(convertObject.getDesDir());
            _dest = file == null ?
                    convertToPdf(convertObject)
                    : file.getName();
        }
        return _dest;
    }

    private List<String> convertToImage(ConvertObject convertObject) throws Exception {
        return pdf2Img(getPath(convertObject), convertObject.getDesDir());
    }

    private boolean isInProcess() {
        return status == STATUS_IN_PROGRESS;
    }

    private boolean isWithError() {
        return status == STATUS_WITH_ERRORS;
    }

//    public static void main(String[] args) throws Exception{
//        new PDFCreatorConvertEngine().convertToImage(DocType.doc, "E:\\test\\3.doc", "E:\\test\\");
//    }

    private synchronized void _convert(Integer type, String source, String path) throws Exception {
        try {
            init(type);
            File destFile = new File(path);
            setCOption("AutosaveDirectory", destFile.getParentFile().getAbsolutePath());
            setCOption("AutosaveFilename", destFile.getName());
            Variant result = pdfCreator.invoke("cPrintfile", source);
            int seconds = 0;
            while (isInProcess()) {
                Thread.sleep(1000);
                seconds++;
                if (seconds > 20) { // timeout
                    break;
                }
            }
            if (seconds > 20 || isWithError()) return;
        } catch (Exception ex) {
            logger.error("转换失败{}", ex.getMessage());
            throw ex;
        } catch (Error ex) {
            logger.error("转换失败{}", ex.getMessage());
            throw ex;
        } finally {
            close();
        }
    }
}
